<template>
  <div id="app" class="theme1">
    <div class="top-title"><h1>欢迎使用柚子编辑器</h1></div>
    <md-head ref="head"></md-head>
    <div class="g_editor_container">
      <div class="editor">
        <Input ref="textarea" class="textarea" :rows="9999" v-model="editorContent" type="textarea" />
      </div>
      <div class="preview" id="preview">
        <div v-html="result"></div>
      </div>
    </div>
  </div>
</template>

<script>
// 以下以import起始为引用当前页面所需的资源（组件、样式、js）
import MdHead from './components/header';  //引入自定义的组件（工具栏组件）
import bus from './lib/bus.js';
import markdown from 'markdown-it'
import hljs from 'highlight.js';
import html2Canvas from 'html2canvas'; // html转换图片插件
import JsPDF from 'jspdf'; // PDF导出插件
import markdownItMark from 'markdown-it-mark';
import markdownItIns from 'markdown-it-ins';
import markdownItEmoji from 'markdown-it-emoji';  
import './assets/theme.css'  // 预览的样式
import 'highlight.js/styles/default.css'
import './assets/theme.less' // 界面样式
import hotkeys from 'hotkeys-js';
import _ from 'lodash'
// 定义当前组件
export default {
  name: 'App', 
  components: {
    MdHead  // 引入header.vue中定义好的工具栏组件
  },
  data () {
    return {
      editorContent: '', // 编辑区内容
      operateHistory: [], // 操作历史
      deleteHistory: [], // 删除历史
      result: '', // 结果
      htmlTitle: '柚子编辑器', 
      markdown: new markdown({
        highlight: function (str, lang) {
          if (lang && hljs.getLanguage(lang)) {
            try {
              return hljs.highlight(lang, str).value;
            } catch (__) { }
          }
          return ''; // 使用额外的默认转义
        }
      }).use(markdownItMark).use(markdownItIns).use(markdownItEmoji).use(require('markdown-it-footnote')).use(require('markdown-it-task-checkbox'))
    }
  },
  // vue 完成了 data 数据的初始化，el没有加载完成时进行的注册
  mounted () {
    hotkeys.filter = () => true
    hotkeys('ctrl+2,command+2,ctrl+3,command+3,ctrl+b,command+b,ctrl+k,command+k,ctrl+u,command+u,ctrl+i,command+i,ctrl+shift+i,command+shift+i,ctrl+z,command+z,ctrl+shift+z,command+shift+z', (event, handler) => {
      event.preventDefault()
      let template = ''
      let bothEnds = ''
      switch (handler.key) {
        case 'ctrl+2': // 二级标题
        case 'command+2':
          template = `
## text  `
          break;
        case 'ctrl+3': // 三级标题
        case 'command+3':
          template = `
### text  `
          break;
        case 'ctrl+b': // 加粗
        case 'command+b':
          template = ' **text** '
          bothEnds = '**'
          break;
        case 'ctrl+k': // 连接
        case 'command+k':
          template = ' [text]( ) '
          break;
        case 'ctrl+u': // 图片上传
        case 'command+u':
          this.$refs.head.insertImage()  // $refs 指向<template></template>标签中的 ref="head" 
          break;

        case 'ctrl+i': // 行内代码
        case 'command+i':
          template = ' `text` '
          break;
        case 'ctrl+shift+i': // 代码块
        case 'command+shift+i':
          template = `
\`\`\`
code here!
\`\`\`
`
          break;
        case 'ctrl+z': // 撤销
        case 'command+z':

          if (this.operateHistory.length < 1) return
          this.deleteHistory.push(this.operateHistory[this.operateHistory.length - 1])
          this.operateHistory.splice(this.operateHistory.length - 1, 1)
          // if (this.operateHistory.length >= 1) { // 最后一步不允许撤销
          //   this.editorContent = this.operateHistory[this.operateHistory.length - 1]
          // }
          var str = this.operateHistory.length ? this.operateHistory[this.operateHistory.length - 1] : ''
          this.editorContent = str
          break;
        case 'ctrl+shift+z': // 恢复
        case 'command+shift+z':
          if (!this.deleteHistory.length) return
          this.editorContent = this.deleteHistory[this.deleteHistory.length - 1]
          this.deleteHistory.splice(this.deleteHistory.length - 1, 1)
          break;
        default:
          template = ''
          break;
      }
      if (!template) return
      this.insertAtCursor(template, bothEnds)
    });

    /** 
     * 操作按钮插入内容
    */
    bus.$on('insert', (string, bothEnds) => {
      this.insertAtCursor(string, bothEnds)
    })
    /** 
     * 导出md文件
    */
    bus.$on('export', () => {
      if (!this.editorContent || !window.localStorage.getItem('MarkdownDraft')) { //判断编辑区是否编辑文字(window.localStorage.getItem('MarkdownDraft') 这个是获取保存在浏览器的编辑区数据， 加!表示没有获取到数据)
        return this.$Notice.error({ title: '你还没有写内容' }) // 编辑区没有内容，返回全局提示信息
      }
      const content = this.editorContent
      const elem = document.createElement('a'); // 创建<a></a>下载标签
      elem.download = 'draft.md'; // 命名下载文件名称
      elem.style.display = 'none'; // 设置创建的<a></a>标签样式为不显示
      const blob = new Blob([content], { type: 'text/plain' }); // 设置请求内容类型为文本text/plain
      elem.href = URL.createObjectURL(blob) // 生成下载文件的URL
      document.body.appendChild(elem); // 把<a></a>标签添加到<body></body>中
      elem.click(); // 自动点击该标签触发下载
      document.body.removeChild(elem); // 然后移除<a></a>下载标签
      // 定时0.3秒清除内容
      setTimeout(() => {
        this.editorContent = ''  // 清空文本区
        window.localStorage.removeItem('MarkdownDraft') // 移除缓存
      }, 300)
    })

    // 导出PDF
    bus.$on('exportPdf',() => {
      if (!this.editorContent || !window.localStorage.getItem('MarkdownDraft')) { //判断编辑区是否编辑文字(window.localStorage.getItem('MarkdownDraft') 这个是获取保存在浏览器的编辑区数据， 加!表示没有获取到数据)
        return this.$Notice.error({ title: '你还没有写内容' }) // 编辑区没有内容，返回全局提示信息
      }else{
        this.getPdf(); // 导出方法
      }
    })

    //更换主题
     bus.$on('changeColor',function(num){
      //把className theme1，theme2挂载在app.vue的<div id="app"></div>上
      document.getElementById('app').className ='theme'+ num ;
      window.localStorage.setItem('app',document.getElementById('app').className)
    })
     
    // 刷新页面（或打开新网页操作）
    // 判断浏览器是否有缓存编辑区数据
    if (!window.localStorage.getItem('MarkdownDraft')) return // 没有则返回空
    this.editorContent = window.localStorage.getItem('MarkdownDraft') || '' // 给编辑区赋值
    this.operateHistory.push(this.editorContent) // 添加到浏览器操作历史记录

    // 判断是否第一次加载页面
    if(!window.localStorage.getItem('app')) { // 如果未从缓存中获取到数据
      document.getElementById('app').className ='theme1'; // 设置默认主题为theme1
      window.localStorage.setItem('app','theme1') // 保存到浏览器缓存中
    } else { // 获取到缓存数据
      document.getElementById('app').className = window.localStorage.getItem('app') // 设置主题为缓存主题
    }
  },
  watch: {
    editorContent: _.debounce(function (current, prev) {
      this.result = this.markdown.render(this.editorContent)
      const history = this.operateHistory
      let str = history.length ? history[history.length - 1] : ''
      if (current !== str) {
        history.push(current)
      }
      this.autoSave()
    }, 0)
  },
  methods: {
    autoSave () { // 自动保存
      window.localStorage.setItem('MarkdownDraft', this.editorContent) // 将编辑区数据保存到浏览器缓存（名称为MarkdownDraft）
    },
    insertAtCursor (myValue, bothEnds) { // 插入到光标所在位置（值，结束文本）
      const myField = document.querySelector('textarea') // 编辑区域 通过标签名称获取
      //IE 浏览器
      if (document.selection) {
        myField.focus(); 
        const sel = document.selection.createRange();
        sel.text = myValue;
        sel.select();
      }

      //FireFox、Chrome等浏览器执行以下插入操作
      else if (myField.selectionStart || myField.selectionStart == '0') { // 先判断编辑区的选中起点是否为起始状态
        const startPos = myField.selectionStart; // 设置起点为起始点 起始点位置==起始终点位置
        const endPos = myField.selectionEnd; // 设置终点为起始终点

        // 插入值
        if (startPos === endPos) { // 起点位置和终点位置相同（）
          myField.value = myField.value.substring(0, startPos) + myValue + myField.value.substring(endPos, myField.value.length);
        } else { // 起点位置和终点位置不相同
          myField.value = myField.value.substring(0, startPos) + bothEnds + myField.value.substring(startPos, endPos) + bothEnds + myField.value.substring(endPos, myField.value.length);
        }
        // 保存滚动条
        const restoreTop = myField.scrollTop;
        if (restoreTop > 0) {
          myField.scrollTop = restoreTop;
        }
        myField.selectionStart = startPos + myValue.length; // 重新计算起点位置
        myField.selectionEnd = startPos + myValue.length; // 重新计算终点位置
      } else {
        myField.value += myValue;
      }
      document.querySelector('textarea').dispatchEvent(new Event('input')); 

    },
    // 导出为PDF
    getPdf() {
      var title = this.htmlTitle  // 获取头部定义的title
      html2Canvas(document.querySelector('#preview'), { //通过html2Canvas将选中标签中内容转换成图片
        allowTaint: true
      }).then(function (canvas) { // 对转换的图片进行操作
        let contentWidth = canvas.width // 设置内容宽度为转换的图片宽度
        let contentHeight = canvas.height // 设置内容高度为转换的图片高度
        let pageHeight = contentWidth / 592.28 * 841.89 // 设置页面宽度为内容宽度
        let leftHeight = contentHeight // 设置页面高度为内容高度
        let position = 0 // 设置起点
        let imgWidth = 595.28 
        let imgHeight = 592.28 / contentWidth * contentHeight 
        let pageData = canvas.toDataURL('image/jpeg', 1.0) // 
        let PDF = new JsPDF('', 'pt', 'a4')
        if (leftHeight < pageHeight) {
          PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight)
        } else {
          while (leftHeight > 0) {
            PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
            leftHeight -= pageHeight
            position -= 841.89
            if (leftHeight > 0) {
              PDF.addPage()
            }
          }
        }
        PDF.save(title + '.pdf')
      })
    }
  }
}
</script>
